import { Node, Rect, Size, UITransform, Vec2, Vec3, math, toRadian } from "cc";

export namespace MyMath {
    const _seg = new Vec2()
    export function isPointInSegment(linePointA: Vec2, linePointB: Vec2, point: Vec2) {
        Vec2.subtract(_seg, linePointB, linePointA)
        
        const factor = (point.x - linePointA.x) / _seg.x
        if (factor < 0 || factor > 1) {
            return false
        }
        else {
            return linePointA.y + _seg.y * factor == point.y
        }
    }

    const _segA = new Vec2()
    const _segB = new Vec2()
    export function isSegmentIntersect (lineAPointA: Vec2, lineAPointB: Vec2, lineBPointA: Vec2, lineBPointB: Vec2) {
        Vec2.subtract(_segA, lineAPointB, lineAPointA)
        Vec2.subtract(_segB, lineBPointB, lineBPointA)

        //lineAPointA + segA * Factor1 = lineBPointA + segB * Factor2
        //lineAPA.x + segA.x * Factor1 = lineBPA.x + segB.x * Factor2   C
        //lineAPA.y + segA.y * Factor1 = lineBPA.y + segB.y * Factor2   D
        //Factor1 = ((lineBPA.x + segB.x * Factor2 + lineBPA.y + segB.y * Factor2) - (lineAPA.y + lineAPA.x)) / (segA.x + segA.y)  C+D
        //Factor1 = Factor2 * (segB.x + segB.y) / (segA.x + segA.y) + (lineBPA.x + lineBPA.y - lineAPA.y - lineAPA.x) / (segA.x + segA.y)
        //segA.x * Factor2 * (segB.x + segB.y) / (segA.x + segA.y) + segA.x * (lineBPA.x + lineBPA.y - lineAPA.y - lineAPA.x) / (segA.x + segA.y) - segB.x * Factor2 = lineBPA.x - lineAPA.x
        //Factor2 = (lineBPA.x - lineAPA.x - segA.x * (lineBPA.x + lineBPA.y - lineAPA.y - lineAPA.x) / (segA.x + segA.y)) / (segA.x * (segB.x + segB.y) / (segA.x + segA.y) - segB.x)

        //平行另作处理
        if ((_segA.y == 0 && _seg.y == 0) ||
            Math.abs(_segA.x / _segA.y) == Math.abs(_segB.x / _segB.y)) {  //平行则看是否有任何一点在另一个线段上
            return isPointInSegment(lineBPointA, lineBPointB, lineAPointA) ||
                   isPointInSegment(lineBPointA, lineBPointB, lineAPointB) ||
                   isPointInSegment(lineAPointA, lineAPointB, lineBPointA) ||
                   isPointInSegment(lineAPointA, lineAPointB, lineBPointB)
        }


        let factor1, factor2
        if (_segA.x + _segB.x == 0) {  //C - D
            factor2 = (lineBPointA.x - lineAPointA.x - _segA.x * (lineBPointA.x - lineBPointA.y - lineAPointA.y + lineAPointA.x) / (_segA.x - _segA.y)) / (_segA.x * (_segB.x - _segB.y) / (_segA.x - _segA.y) - _segB.x)
            factor1 = factor2 * (_segB.x - _segB.y) / (_segA.x - _segA.y) + (lineBPointA.x - lineBPointA.y - lineAPointA.y + lineAPointA.x) / (_segA.x - _segA.y)
        }
        else { //C + D
            factor2 = (lineBPointA.x - lineAPointA.x - _segA.x * (lineBPointA.x + lineBPointA.y - lineAPointA.y - lineAPointA.x) / (_segA.x + _segA.y)) / (_segA.x * (_segB.x + _segB.y) / (_segA.x + _segA.y) - _segB.x)
            factor1 = factor2 * (_segB.x + _segB.y) / (_segA.x + _segA.y) + (lineBPointA.x + lineBPointA.y - lineAPointA.y - lineAPointA.x) / (_segA.x + _segA.y)
        }

        return (factor1 >= 0 && factor1 <= 1) && (factor2 >= 0 && factor2 <= 1)
    }

    export function isRectIntersect(linesA: Vec2[][], linesB: Vec2[][]) {  //两个矩形线段
        // const radiusA = toRadian(angleA)
        // const pointA_RT = new Vec2(rectA.xMax, rectA.yMax).rotate(radiusA)
        // const pointA_RB = new Vec2(rectA.xMax, rectA.yMin).rotate(radiusA)
        // const pointA_LB = new Vec2(rectA.xMin, rectA.yMin).rotate(radiusA)
        // const pointA_LT = new Vec2(rectA.xMin, rectA.yMax).rotate(radiusA)

        // const radiusB = toRadian(angleB)
        // const pointB_RT = new Vec2(rectB.xMax, rectB.yMax).rotate(radiusB)
        // const pointB_RB = new Vec2(rectB.xMax, rectB.yMin).rotate(radiusB)
        // const pointB_LB = new Vec2(rectB.xMin, rectB.yMin).rotate(radiusB)
        // const pointB_LT = new Vec2(rectB.xMin, rectB.yMax).rotate(radiusB)

        // const LinesA = [[pointA_RT, pointA_RB], [pointA_RB, pointA_LB], [pointA_LB, pointA_LT], [pointA_LT, pointA_RT]]
        // const LinesB = [[pointB_RT, pointB_RB], [pointB_RB, pointB_LB], [pointB_LB, pointB_LT], [pointB_LT, pointB_RT]]

        const lineA = linesA.find(lineA => {
            return linesB.find(lineB => {
                return isSegmentIntersect(lineA[0], lineA[1], lineB[0], lineB[1])
            })
        })

        if (lineA) {
            return true
        }
        else { //todo  补充点被矩形包含  矩形包含
            return false
        }
    }
}

export namespace GameUtils {
    export function getNodeBoundingBox(node: Node) {
        const uitrans = node.getComponent(UITransform)
        const size = uitrans.contentSize
        const scale = node.scale
        const radius =  toRadian(node.angle)
        size.set(size.width * scale.x, size.height * scale.y)
        const halfWidth = size.width / 2
        const halfHeight = size.height / 2
        const lt = new Vec2(-halfWidth, halfHeight)
        const rt = new Vec2(halfWidth, halfHeight)
        const rb = new Vec2(halfWidth, -halfHeight)
        const lb = new Vec2(-halfWidth, -halfHeight)

        lt.rotate(radius)
        rt.rotate(radius)
        rb.rotate(radius)
        lb.rotate(radius)

        const minX = Math.min(lt.x, lb.x)
        const maxX = Math.max(rt.x, rb.x)
        const minY = Math.min(rb.y, lb.y)
        const maxY = Math.max(lt.y, rt.y)

        const rect = new Rect(minX, minY, maxX - minX, maxY - minY)
        rect.x += node.position.x //todo  先做锚点为中心的   锚点为非中心 计算中心偏离量 * 缩放
        rect.y += node.position.y

        return rect
    }

    const _size = new Size()
    const _pos = new Vec3()
    export function getNodeRectLines(node: Node, angle?: number, otherNodeSpace?: Node) { //获取当前节点的包围盒的四条线段 //涵盖旋转
        _size.set(node.getComponent(UITransform).contentSize)
        const scale = node.scale
        _size.set(_size.width * scale.x, _size.height * scale.y)

        otherNodeSpace = otherNodeSpace || node.parent
        otherNodeSpace.getComponent(UITransform).convertToNodeSpaceAR(node.worldPosition, _pos)

        const halfW = _size.width / 2
        const halfH = _size.height / 2
        
        //锚点如果不是中心 则有问题 todo
        const radius = isNaN(angle) ? toRadian(node.angle) : toRadian(angle)
        const RT = new Vec2(halfW, halfH).rotate(radius).add2f(_pos.x, _pos.y)
        const RB = new Vec2(halfW, -halfH).rotate(radius).add2f(_pos.x, _pos.y)
        const LB = new Vec2(-halfW, -halfH).rotate(radius).add2f(_pos.x, _pos.y)
        const LT = new Vec2(-halfW, halfH).rotate(radius).add2f(_pos.x, _pos.y)

        return [[RT, RB], [RB, LB], [LB, LT], [LT, RT]]
    }
}

export namespace CommonUtils {
    export function lastIndexOf<T>(arr: T[], ele: T) {
        let index = -1
        arr.forEach((e, i) => {
            if (e == ele) {
                index = i
            }
        })

        return index
    }

    export function findLastIndex<T>(arr: T[], func: (ele: T, index: number) => boolean) {
        let index = -1
        arr.forEach((ele, i) => {
            if (func(ele, i)) {
                index = i
            }
        })

        return index
    }
}

